#include "wx/wxprec.h"
// standard
#if defined(__WXMSW__) && !defined(__GNUWIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__)

#ifndef __SALFORDC__
#define   WIN32_LEAN_AND_MEAN
#define   NOSERVICE
#define   NOIME
#define   NOATOM
#define   NOGDI
#define   NOGDICAPMASKS
#define   NOMETAFILE
#define   NOMINMAX
#define   NOMSG
#define   NOOPENFILE
#define   NORASTEROPS
#define   NOSCROLL
#define   NOSOUND
#define   NOSYSMETRICS
#define   NOTEXTMETRIC
#define   NOWH
#define   NOCOMM
#define   NOKANJI
#define   NOCRYPT
#define   NOMCX
#endif

#elif defined(__WXMSW__) && defined(__WXWINCE__)
#include  "wx/msw/missing.h"
#elif (defined(__OS2__))
#include <io.h>
#elif (defined(__UNIX__) || defined(__GNUWIN32__))
#include  <unistd.h>
#include  <time.h>
#include  <sys/stat.h>
#elif defined(__DOS__)
#if defined(__WATCOMC__)
#include <io.h>
#elif defined(__DJGPP__)
#include <io.h>
#include <unistd.h>
#include <stdio.h>
#else
#error  "Please specify the header with file functions declarations."
#endif
#elif (defined(__WXSTUBS__))
// Have to ifdef this for different environments
#include <io.h>
#elif (defined(__WXMAC__))
#if __MSL__ < 0x6000
int access( const char *path, int mode ) { return 0 ; }
#else
int _access( const char *path, int mode ) { return 0 ; }
#endif
char* mktemp( char * path ) { return path ;}
#include <stat.h>
#include <unistd.h>
#else
#error  "Please specify the header with file functions declarations."
#endif  //Win/UNIX

#include  <stdio.h>       // SEEK_xxx constants

// Windows compilers don't have these constants
#ifndef W_OK
enum {
  F_OK = 0,   // test for existence
  X_OK = 1,   //          execute permission
  W_OK = 2,   //          write
  R_OK = 4    //          read
};
#endif // W_OK

#ifdef __SALFORDC__
#include <unix.h>
#endif

// some broken compilers don't have 3rd argument in open() and creat()
#ifdef __SALFORDC__
#define ACCESS(access)
#define stat    _stat
#else // normal compiler
#define ACCESS(access)  , (access)
#endif // Salford C

#include  "wx/filename.h"
#include  "wx/file.h"
#include  "wx/filefn.h"

#define   O_BINARY    (0)

#ifndef MAX_PATH
#define MAX_PATH 512
#endif

bool wxFile::Exists( const wxChar *name ) {
  return wxFileExists( name );
}

bool wxFile::Access( const wxChar *name, OpenMode mode ) {
  int how;
  switch( mode ) {
    default:
      wxFAIL_MSG( wxT( "wxFile::Access 参数格式错误." ) );
    case read:
      how = R_OK;
      break;
    case write:
      how = W_OK;
      break;
    case read_write:
      how = R_OK | W_OK;
      break;
  }
  return wxAccess( name, how ) == 0;
}

wxFile::wxFile( const wxChar *szFileName, OpenMode mode ) {
  m_fd = fd_invalid;
  m_error = false;
  Open( szFileName, mode );
}

bool wxFile::Create( const wxChar *szFileName, bool bOverwrite, int accessMode ) {
  int fd = wxOpen( szFileName, O_BINARY | O_WRONLY | O_CREAT | ( bOverwrite ? O_TRUNC : O_EXCL ) ACCESS( accessMode ) );
  if( fd == -1 ) {
    wxLogSysError( _( "无法创建文件 '%s'" ), szFileName );
    return false;
  }
  Attach( fd );
  return true;
}

bool wxFile::Open( const wxChar *szFileName, OpenMode mode, int accessMode ) {
  int flags = O_BINARY;
  switch( mode ) {
    case read:
      flags |= O_RDONLY;
      break;
    case write_append:
      if( wxFile::Exists( szFileName ) ) {
        flags |= O_WRONLY | O_APPEND;
        break;
      }
    case write:
      flags |= O_WRONLY | O_CREAT | O_TRUNC;
      break;
    case write_excl:
      flags |= O_WRONLY | O_CREAT | O_EXCL;
      break;
    case read_write:
      flags |= O_RDWR;
      break;
  }
  int fd = wxOpen( szFileName, flags ACCESS( accessMode ) );
  if( fd == -1 ) {
    wxLogSysError( _( "无法打开文件 '%s'" ), szFileName );
    return false;
  }
  Attach( fd );
  return true;
}

bool wxFile::Close() {
  if( IsOpened() ) {
    if( wxClose( m_fd ) == -1 ) {
      wxLogSysError( _( "无法关闭文件描述符 %d" ), m_fd );
      m_fd = fd_invalid;
      return false;
    } else {
      m_fd = fd_invalid;
    }
  }
  return true;
}

ssize_t wxFile::Read( void *pBuf, size_t nCount ) {
  wxCHECK( ( pBuf != NULL ) && IsOpened(), 0 );
  ssize_t iRc = wxRead( m_fd, pBuf, nCount );
  if( iRc == -1 ) {
    wxLogSysError( _( "无法读取文件描述符 %d" ), m_fd );
    return wxInvalidOffset;
  }
  return iRc;
}

size_t wxFile::Write( const void *pBuf, size_t nCount ) {
  wxCHECK( ( pBuf != NULL ) && IsOpened(), 0 );
  ssize_t iRc = wxWrite( m_fd, pBuf, nCount );
  if( iRc == -1 ) {
    wxLogSysError( _( "无法写入文件描述符 %d" ), m_fd );
    m_error = true;
    iRc = 0;
  }
  return iRc;
}

bool wxFile::Flush() {
  if( IsOpened() && GetKind() == wxFILE_KIND_DISK ) {
    if( wxFsync( m_fd ) == -1 ) {
      wxLogSysError( _( "无法刷新文件描述符 %d" ), m_fd );
      return false;
    }
  }
  return true;
}

wxFileOffset wxFile::Seek( wxFileOffset ofs, wxSeekMode mode ) {
  wxASSERT_MSG( IsOpened(), _T( "无法在关闭的文件上查找" ) );
  wxCHECK_MSG( ofs != wxInvalidOffset || mode != wxFromStart, wxInvalidOffset, _T( "无效的绝对文件偏移量" ) );
  int origin;
  switch( mode ) {
    default:
      wxFAIL_MSG( _( "未知的搜索源" ) );
    case wxFromStart:
      origin = SEEK_SET;
      break;
    case wxFromCurrent:
      origin = SEEK_CUR;
      break;
    case wxFromEnd:
      origin = SEEK_END;
      break;
  }
  wxFileOffset iRc = wxSeek( m_fd, ofs, origin );
  if( iRc == wxInvalidOffset ) {
    wxLogSysError( _( "无法在文件描述符上查找 %d" ), m_fd );
  }
  return iRc;
}

// get current file offset
wxFileOffset wxFile::Tell() const {
  wxASSERT( IsOpened() );
  wxFileOffset iRc = wxTell( m_fd );
  if( iRc == wxInvalidOffset ) {
    wxLogSysError( _( "无法在文件描述符上获取查找位置 %d" ), m_fd );
  }
  return iRc;
}

// get current file length
wxFileOffset wxFile::Length() const {
  wxASSERT( IsOpened() );
  wxFileOffset iRc = Tell();
  if( iRc != wxInvalidOffset ) {
    // have to use const_cast :-(
    wxFileOffset iLen = ( ( wxFile * )this )->SeekEnd();
    if( iLen != wxInvalidOffset ) {
      // restore old position
      if( ( ( wxFile * )this )->Seek( iRc ) == wxInvalidOffset ) {
        // error
        iLen = wxInvalidOffset;
      }
    }
    iRc = iLen;
  }
  if( iRc == wxInvalidOffset ) {
    wxLogSysError( _( "在文件描述符上找不到文件的长度 %d" ), m_fd );
  }
  return iRc;
}

// 是否已到达文件结尾？
bool wxFile::Eof() const {
  wxASSERT( IsOpened() );
  wxFileOffset iRc;
  wxFileOffset ofsCur = Tell(), ofsMax = Length();
  if( ofsCur == wxInvalidOffset || ofsMax == wxInvalidOffset ) {
    iRc = wxInvalidOffset;
  } else {
    iRc = ofsCur == ofsMax;
  }
  if( iRc == 1 ) {}
  else if( iRc == 0 ) {
    return false;
  } else if( iRc == wxInvalidOffset ) {
    wxLogSysError( _( "无法确定是否已到达描述符上的文件结尾 %d" ), m_fd );
  } else {
    wxFAIL_MSG( _( "无效的eof（）返回值." ) );
  }
  return true;
}

wxTempFile::wxTempFile( const wxString& strName ) {
  Open( strName );
}

bool wxTempFile::Open( const wxString& strName ) {
  wxFileName fn( strName );
  if( !fn.IsAbsolute() ) {
    fn.Normalize( wxPATH_NORM_ABSOLUTE );
  }
  m_strName = fn.GetFullPath();
  m_strTemp = wxFileName::CreateTempFileName( m_strName, &m_file );
  if( m_strTemp.empty() ) {
    // CreateTempFileName() failed
    return false;
  }
  mode_t mode;
  wxStructStat st;
  if( stat( ( const char* ) m_strName.fn_str(), &st ) == 0 ) {
    mode = st.st_mode;
  } else {
    mode_t mask = umask( 0777 );
    mode = 0666 & ~mask;
    umask( mask );
  }
  if( chmod( ( const char* ) m_strTemp.fn_str(), mode ) == -1 ) {
    wxLogSysError( _( "无法设置临时文件权限" ) );
  }
  return true;
}

wxTempFile::~wxTempFile() {
  if( IsOpened() ) {
    Discard();
  }
}

bool wxTempFile::Commit() {
  m_file.Close();
  if( wxFile::Exists( m_strName ) && wxRemove( m_strName ) != 0 ) {
    wxLogSysError( _( "无法删除文件 '%s'" ), m_strName.c_str() );
    return false;
  }
  if( !wxRenameFile( m_strTemp, m_strName ) ) {
    wxLogSysError( _( "无法提交对文件的更改 '%s'" ), m_strName.c_str() );
    return false;
  }
  return true;
}

void wxTempFile::Discard() {
  m_file.Close();
  if( wxRemove( m_strTemp ) != 0 ) {
    wxLogSysError( _( "无法删除临时文件 '%s'" ), m_strTemp.c_str() );
  }
}

